use lazy_static::lazy_static;
use simplelog;
use log::{info};
use simplelog::{WriteLogger};
use std::ffi::CString;
use std::os::raw::c_char;

mod hacker;
mod mem_helper;
mod cam_config;

mod iplugin;
mod chase_cam;

lazy_static!(
    static ref CHASECAM: std::sync::Mutex<chase_cam::ChaseCamPlugin> = std::sync::Mutex::new(chase_cam::ChaseCamPlugin::new());
);

#[no_mangle]
extern fn rbn_init() -> *const c_char {
    let mut plugin = CHASECAM.lock().unwrap();
    plugin.init();
    plugin.get_name()
}

#[no_mangle]
extern fn rbn_on_game_mode_changed() {
    let mut plugin = CHASECAM.lock().unwrap();
    plugin.on_game_mode_changed();
}

#[no_mangle]
extern fn rbn_on_end_frame() {
    let mut plugin = CHASECAM.lock().unwrap();
    plugin.on_end_frame();
}

#[no_mangle]
pub extern "C" fn RBR_CreatePlugin(game: *mut std::ffi::c_void) -> *mut std::ffi::c_void {
    if let Some(game_path) = std::env::current_exe().unwrap().parent() {
        let plugin_path = game_path.join("Plugins").join("RBRFluentChaseCam");
        let log_file = plugin_path.join("rbr_chase_cam.log");
        let hacker_file = plugin_path.join("RBRHackLayer.log");
        if !plugin_path.exists() {
            std::fs::create_dir(plugin_path).unwrap();
        }
        WriteLogger::init(log::LevelFilter::Info, 
            simplelog::Config::default(), std::fs::File::create(log_file).unwrap()).unwrap();
        let hacker_logfile = CString::new(hacker_file.into_os_string().into_string().unwrap()).expect("Failed to construct hacker layer log filepath.");
        unsafe {hacker::RBR_InitLogger(hacker_logfile.as_ptr())};
    }

    
    info!("Create Plugin RBRFluentChaseCam [{}] with arg: {:?}", std::env!("CARGO_PKG_VERSION"), game);

    unsafe {
        let plugin = hacker::RBR_InitPlugin(game);
        hacker::RBR_SetInitialize(rbn_init);
        hacker::RBR_SetOnGameModeChanged(rbn_on_game_mode_changed);
        hacker::RBR_SetOnEndScene(rbn_on_end_frame);

        return plugin;
    };
}

#[no_mangle]
pub extern "system" fn DllMain(_: usize, _: u32, _: usize) -> i32 {
    println!("DllMain");
    1
}

